#ifndef SWIIC_H_
#define SWIIC_H_

#include "stdint.h"

#ifdef __cplusplus
extern "C"
{
#endif

	typedef enum
	{
		SW_IIC_ACK = 0,
		SW_IIC_NACK = 1
	} sw_iic_ack_type;

	typedef struct
	{
		void (*sda_out_high)(void);
		void (*sda_out_low)(void);

		void (*scl_out_high)(void);
		void (*scl_out_low)(void);

		void (*scl_out_mode)(void);
		void (*sda_out_mode)(void);
		void (*sda_in_mode)(void);

		uint8_t (*sda_st_get)(void);
	} swiic_cfg_type;

	void sw_iic_init(const swiic_cfg_type *iicobj);

	void sw_iic_start(const swiic_cfg_type *iicobj);

	void sw_iic_stop(const swiic_cfg_type *iicobj);

	void sw_iic_ack_send(const swiic_cfg_type *iic, sw_iic_ack_type a);

	sw_iic_ack_type sw_iic_send_byte(const swiic_cfg_type *iicobj, uint8_t c);

	uint8_t sw_iic_rcv_byte(const swiic_cfg_type *iicobj);

	sw_iic_ack_type sw_iic_send_xbits(const swiic_cfg_type *iic, uint32_t c, uint8_t bits_len);

	uint32_t sw_iic_rcv_xbits(const swiic_cfg_type *iic, uint8_t bits_len);

	sw_iic_ack_type sw_iic_chip_rcv_byte(const swiic_cfg_type *iicobj, uint8_t sla, uint8_t *c);

	sw_iic_ack_type sw_iic_chip_send_byte(const swiic_cfg_type *iicobj, uint8_t sla, uint8_t c);

	sw_iic_ack_type sw_iic_chip_send_str(const swiic_cfg_type *iicobj, uint8_t sla, uint8_t suba, uint8_t *s, uint8_t no);

	sw_iic_ack_type sw_iic_chip_rcv_str(const swiic_cfg_type *iicobj, uint8_t sla, uint8_t suba, uint8_t *s, uint8_t no);

	sw_iic_ack_type sw_iic_chip2_send_str(const swiic_cfg_type *iic, uint8_t sla, uint16_t suba, uint8_t *s, uint16_t no);

	sw_iic_ack_type sw_iic_chip2_rcv_str(const swiic_cfg_type *iic, uint8_t sla, uint16_t suba, uint8_t *s, uint16_t no);

	void sw_hiic_init(const swiic_cfg_type *iicobj);

	void sw_hiic_start(const swiic_cfg_type *iicobj);

	void sw_hiic_stop(const swiic_cfg_type *iicobj);

	void sw_hiic_ack_send(const swiic_cfg_type *iic, sw_iic_ack_type a);

	sw_iic_ack_type sw_hiic_send_byte(const swiic_cfg_type *iicobj, uint8_t c);

	uint8_t sw_hiic_rcv_byte(const swiic_cfg_type *iicobj);

	sw_iic_ack_type sw_hiic_send_xbits(const swiic_cfg_type *hiic, uint32_t c, uint8_t bits_len);

	uint32_t sw_hiic_rcv_xbits(const swiic_cfg_type *hiic, uint8_t bits_len);

	sw_iic_ack_type sw_hiic_chip_rcv_byte(const swiic_cfg_type *iicobj, uint8_t sla, uint8_t *c);

	sw_iic_ack_type sw_hiic_chip_send_byte(const swiic_cfg_type *iicobj, uint8_t sla, uint8_t c);

	sw_iic_ack_type sw_hiic_chip_send_str(const swiic_cfg_type *iicobj, uint8_t sla, uint8_t suba, uint8_t *s, uint8_t no);

	sw_iic_ack_type sw_hiic_chip_rcv_str(const swiic_cfg_type *iicobj, uint8_t sla, uint8_t suba, uint8_t *s, uint8_t no);

	sw_iic_ack_type sw_hiic_chip2_send_str(const swiic_cfg_type *iic, uint8_t sla, uint16_t suba, uint8_t *s, uint16_t no);

	sw_iic_ack_type sw_hiic_chip2_rcv_str(const swiic_cfg_type *iic, uint8_t sla, uint16_t suba, uint8_t *s, uint16_t no);

	typedef struct
	{
		sw_iic_ack_type (*rcv_byte)(uint8_t sla, uint8_t *c);
		sw_iic_ack_type (*send_byte)(uint8_t sla, uint8_t c);
		sw_iic_ack_type (*send_str)(uint8_t sla, uint8_t suba, uint8_t *s, uint8_t no);
		sw_iic_ack_type (*rcv_str)(uint8_t sla, uint8_t suba, uint8_t *s, uint8_t no);
		sw_iic_ack_type (*send_str_a2)(uint8_t sla, uint16_t suba, uint8_t *s, uint16_t no);
		sw_iic_ack_type (*rcv_str_a2)(uint8_t sla, uint16_t suba, uint8_t *s, uint16_t no);
	} iic_obj_fun_type;

	typedef struct
	{
		void (*start)(void);
		void (*stop)(void);
		sw_iic_ack_type (*snd_byte)(uint8_t dat); 
		uint8_t (*rcv_byte)(void);
		void (*ack_send)(sw_iic_ack_type);
		const iic_obj_fun_type *fun;
	} iic_obj_type;

	sw_iic_ack_type iic_chip_rcv_byte(const iic_obj_type *iicobj, uint8_t sla, uint8_t *c);

	sw_iic_ack_type iic_chip_send_byte(const iic_obj_type *iicobj, uint8_t sla, uint8_t c);

	sw_iic_ack_type iic_chip_send_str(const iic_obj_type *iicobj, uint8_t sla, uint8_t suba, uint8_t *s, uint8_t no);

	sw_iic_ack_type iic_chip_rcv_str(const iic_obj_type *iicobj, uint8_t sla, uint8_t suba, uint8_t *s, uint8_t no);

	sw_iic_ack_type iic_chip2_send_str(const iic_obj_type *iic, uint8_t sla, uint16_t suba, uint8_t *s, uint16_t no);

	sw_iic_ack_type iic_chip2_rcv_str(const iic_obj_type *iic, uint8_t sla, uint16_t suba, uint8_t *s, uint16_t no);

#define iic_obj_fun_make(obj)                                                                                                                            \
	sw_iic_ack_type obj##_iic_chip_rcv_byte(uint8_t sla, uint8_t *c);                                                                                    \
	sw_iic_ack_type obj##_iic_chip_send_byte(uint8_t sla, uint8_t c);                                                                                    \
	sw_iic_ack_type obj##_iic_chip_send_str(uint8_t sla, uint8_t suba, uint8_t *s, uint8_t no);                                                          \
	sw_iic_ack_type obj##_iic_chip_rcv_str(uint8_t sla, uint8_t suba, uint8_t *s, uint8_t no);                                                           \
	sw_iic_ack_type obj##_iic_chip2_send_str(uint8_t sla, uint16_t suba, uint8_t *s, uint16_t no);                                                       \
	sw_iic_ack_type obj##_iic_chip2_rcv_str(uint8_t sla, uint16_t suba, uint8_t *s, uint16_t no);                                                        \
                                                                                                                                                         \
	sw_iic_ack_type obj##_iic_chip_rcv_byte(uint8_t sla, uint8_t *c) { return iic_chip_rcv_byte(&obj, sla, c); }                                         \
	sw_iic_ack_type obj##_iic_chip_send_byte(uint8_t sla, uint8_t c) { return iic_chip_send_byte(&obj, sla, c); }                                        \
	sw_iic_ack_type obj##_iic_chip_send_str(uint8_t sla, uint8_t suba, uint8_t *s, uint8_t no) { return iic_chip_send_str(&obj, sla, suba, s, no); }     \
	sw_iic_ack_type obj##_iic_chip_rcv_str(uint8_t sla, uint8_t suba, uint8_t *s, uint8_t no) { return iic_chip_rcv_str(&obj, sla, suba, s, no); }       \
	sw_iic_ack_type obj##_iic_chip2_send_str(uint8_t sla, uint16_t suba, uint8_t *s, uint16_t no) { return iic_chip2_send_str(&obj, sla, suba, s, no); } \
	sw_iic_ack_type obj##_iic_chip2_rcv_str(uint8_t sla, uint16_t suba, uint8_t *s, uint16_t no) { return iic_chip2_rcv_str(&obj, sla, suba, s, no); }   \
                                                                                                                                                         \
	const iic_obj_fun_type obj##_api = {                                                                                                                 \
		obj##_iic_chip_rcv_byte,                                                                                                                         \
		obj##_iic_chip_send_byte,                                                                                                                        \
		obj##_iic_chip_send_str,                                                                                                                         \
		obj##_iic_chip_rcv_str,                                                                                                                          \
		obj##_iic_chip2_send_str,                                                                                                                        \
		obj##_iic_chip2_rcv_str,                                                                                                                         \
	}
#define iic_obj_fun_ref(obj) extern const iic_obj_fun_type obj##_api
#define iic_obj_fun_name(obj) &obj##_api

#ifdef __cplusplus
}
#endif

#endif 
